<!DOCTYPE html>
<html>
<head>
    <!-- from: https://bl.ocks.org/valex/98dceff49e0f31c1efdf31a47c15f8f2 -->
    <title>Example 08.03 - Save & Load</title>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>
    <div id="Stats-output"></div>
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>

    <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/dat-gui/0.7.7/dat.gui.min.js" type="text/javascript"></script>
    <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/three.js/110/three.min.js" type="application/javascript"></script>
    <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/stats.js/16/Stats.min.js" type="text/javascript"></script>
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">

        // once everything is loaded, we run our Three.js stuff.
        function init() {

            var stats = initStats();

            // create a scene, that will hold all our elements such as objects, cameras and lights.
            var scene = new THREE.Scene();

            // create a camera, which defines where we're looking at.
            var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

            // create a render and set the size
            var webGLRenderer = new THREE.WebGLRenderer();
            webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE));
            webGLRenderer.setSize(window.innerWidth, window.innerHeight);
            webGLRenderer.shadowMap.enabled = true;
            webGLRenderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap

            var knot = createMesh(new THREE.TorusKnotGeometry(10, 1, 64, 8, 2, 3));
            // add the sphere to the scene
            scene.add(knot);

            // position and point the camera to the center of the scene
            camera.position.x = -30;
            camera.position.y = 40;
            camera.position.z = 50;
            camera.lookAt(new THREE.Vector3(-20, 0, 0));

            // add the output of the renderer to the html element
            document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

            // call the render function
            var step = 0;


            var loadedMesh;

            // setup the control gui
            var controls = new function () {

                console.log(knot.geometry.parameters);
                // we need the first child, since it's a multimaterial
                this.radius = 10;
                this.tube = 1;
                this.radialSegments = 64;
                this.tubularSegments = 8;
                this.p = knot.geometry.parameters.p;
                this.q = knot.geometry.parameters.q;
                this.heightScale = 1;

                this.redraw = function () {
                    // remove the old plane
                    scene.remove(knot);
                    // create a new one
                    knot = createMesh(new THREE.TorusKnotGeometry(controls.radius, controls.tube, Math.round(controls.radialSegments), Math.round(controls.tubularSegments), Math.round(controls.p), Math.round(controls.q)).scale(controls.heightScale,controls.heightScale,controls.heightScale));

                    // add it to the scene.
                    scene.add(knot);
                };

                this.save = function () {
                    var result = knot.toJSON();
                    localStorage.setItem("json", JSON.stringify(result));
                };

                this.load = function () {

                    scene.remove(loadedMesh);

                    var json = localStorage.getItem("json");

                    if (json) {
                        var loadedGeometry = JSON.parse(json);
                        var loader = new THREE.ObjectLoader();

                        loadedMesh = loader.parse(loadedGeometry);
                        loadedMesh.position.x -= 50;
                        scene.add(loadedMesh);
                    }
                }
            };

            var gui = new dat.GUI();
            var ioGui = gui.addFolder('Save & Load');
            ioGui.add(controls, 'save').onChange(controls.save);
            ioGui.add(controls, 'load').onChange(controls.load);
            var meshGui = gui.addFolder('mesh');
            meshGui.add(controls, 'radius', 0, 40).onChange(controls.redraw);
            meshGui.add(controls, 'tube', 0, 40).onChange(controls.redraw);
            meshGui.add(controls, 'radialSegments', 0, 400).step(1).onChange(controls.redraw);
            meshGui.add(controls, 'tubularSegments', 1, 20).step(1).onChange(controls.redraw);
            meshGui.add(controls, 'p', 1, 10).step(1).onChange(controls.redraw);
            meshGui.add(controls, 'q', 1, 15).step(1).onChange(controls.redraw);
            meshGui.add(controls, 'heightScale', 0, 5).onChange(controls.redraw);


            render();

            function createMesh(geom) {

                // assign two materials
                var meshMaterial = new THREE.MeshBasicMaterial({
                    vertexColors: THREE.VertexColors,
                    wireframe: true,
                    wireframeLinewidth: 2,
                    color: 0xaaaaaa
                });
                meshMaterial.side = THREE.DoubleSide;

                // create a multimaterial
                var mesh = new THREE.Mesh(geom, meshMaterial);

                return mesh;
            }

            function render() {
                stats.update();

                knot.rotation.y = step += 0.01;

                // render using requestAnimationFrame
                requestAnimationFrame(render);
                webGLRenderer.render(scene, camera);
            }

            function initStats() {

                var stats = new Stats();
                stats.setMode(0); // 0: fps, 1: ms

                // Align top-left
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.left = '0px';
                stats.domElement.style.top = '0px';

                document.getElementById("Stats-output").appendChild(stats.domElement);

                return stats;
            }
        }
        window.onload = init;
    </script>
</body>
</html>